package keye.document_manage.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import keye.document_manage.dao.sqlserver.IsFilesDao;
import keye.document_manage.entity.Page;
import keye.document_manage.entity.SelectParameters;
import keye.document_manage.gui.ProgressFrame;
import keye.document_manage.service.IFilesCheckService;
import keye.document_manage.util.FileUtil;

@Service("filesCheckService")
public class FilesCheckServiceImpl implements IFilesCheckService{

	@Resource
	private IsFilesDao filesDao;
	
	static int nThread = Runtime.getRuntime().availableProcessors()+1;
	static ExecutorService executorService = Executors.newFixedThreadPool(nThread);
	
	public void setFilesDao(IsFilesDao filesDao) {
		this.filesDao = filesDao;
	}

	@Override
	public Integer checkFiles(ProgressFrame progressFrame, String osPosition,	String logPath, List<SelectParameters> selectParas,	String... tableNames) {
		int result=0;
		if(!logPath.endsWith(".txt"))
			logPath = logPath+File.separator+"log.txt";
		Path filePath = Paths.get(logPath);
		
		List<CompletableFuture<Map<String,String>>> futures = new ArrayList<CompletableFuture<Map<String,String>>>(nThread);

		Page page = new Page(1);
		filesDao.getFilePathInfoByPage(selectParas, page, tableNames);
		long totalNumber = page.getTotalNumber();
		System.out.println("原文总数："+totalNumber);
		long tmp = totalNumber/nThread;
		if(totalNumber<500){
			page.setPageNumberNotCount(1000);
		}else if(tmp > 100000){
			page.setPageNumberNotCount(100000);
		}else{
			page.setPageNumberNotCount(tmp);
		}
		String tempName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		List<Path> tempPath = new ArrayList<Path>();
		for (int i=0; ; i++) {
			List<HashMap<String, Object>> v = filesDao.getFilePathInfoByPage(selectParas, page, tableNames);
			Path p = Paths.get(filePath.getParent()+File.separator+i+tempName+".tmp");
			tempPath.add(p);
			String progress = "0/"+v.size();
			int index = progressFrame.addOneCheck(tableNames[0], progress);
			futures.add(CompletableFuture.supplyAsync( () -> writeSomethigsTmpe(v, osPosition, p,progressFrame,index), executorService));
			if(page.getCurrentPage() >= page.getTotalPage()){
				break;
			}
			page.setCurrentPage(page.getCurrentPage()+1);
		}
		stitchingFile(futures, filePath, tempPath);

		return result;
	}

	/**
	 * 合并临时文件，生成校验日志
	 * @param futures	获得线程结果
	 * @param filePath	日志路径
	 * @param tempPath	存放临时文件的路径
	 */
	protected void stitchingFile(List<CompletableFuture<Map<String,String>>> futures, Path filePath, List<Path> tempPath) {
		try {
			Date date = new Date();
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
			String lastArchiveNo = "";
			Count num = new Count();
			int result=0;
			for (int i = 0; i < futures.size(); i++) {
				Map<String,String> map = futures.get(i).get();
				if(map==null){
					System.out.println("-------------map==null"+i+"  "+futures.get(i).toString());
					continue;
				}
				if(i==0){
					Files.write(filePath, (sdf.format(date)+" 校验日志："+System.getProperty("line.separator")).getBytes(), Files.exists(filePath)?StandardOpenOption.APPEND:StandardOpenOption.CREATE);
				}
				int r = Integer.parseInt(map.get("result"));
				result += r;
				Path tp = tempPath.get(i);
				if(r!=0){
					//cdg 2016-3-24 11:20:20 add
					if(lastArchiveNo==null){
						lastArchiveNo = "";
					}
					//如果第一个档号和上一个档号是一样的则归为同一个，不然则直接加在后面
					if(lastArchiveNo.equals(map.get("firstArchiveNo"))){
						System.out.println("------------firstArchiveNo == lastArchiveNo---------------"+lastArchiveNo);
						BufferedReader reader = Files.newBufferedReader(tp);
						reader.lines().forEach( line->{
							try {
								//跳过第一行
								if(num.getProgressV()>1){
									if(line.startsWith("%num%")){
										num.setProgress(3);
										num.setCount(1);
										Files.write(filePath, (line.replace("%num%", ""+num.getNum())+System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
									}
									else{
										if(num.getProgressV()==2)
											Files.write(filePath, (line.replace(".*[.]", "\t"+num.getCount()+".")+System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
										else{
											num.getCount();
											Files.write(filePath, (line+System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
										}
									}
								}else{
									num.setProgress(2);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}});
						num.setProgress(1);
					}else {
						BufferedReader reader = Files.newBufferedReader(tp);
						reader.lines().forEach(line->{
							try {
								if(line.startsWith("%num%")){
									num.setCount(1);
									Files.write(filePath, (line.replaceFirst("%num%", ""+num.getNum())+System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
								}
								else{
									num.getCount();
									Files.write(filePath, (line+System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}});
					}
					Files.write(filePath, System.getProperty("line.separator").getBytes(), StandardOpenOption.APPEND);
					lastArchiveNo = map.get("lastArchiveNo");
				}
				Files.deleteIfExists(tp);
				System.out.println("--------------delete file : "+tp.getFileName());
				
			}
			if(result==0)
				Files.write(filePath, ("没有发现错误信息！"+System.getProperty("line.separator")+System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 校验原文，结果存放在临时文件中
	 * @param values 需要校验的原文数据
	 * @param osPosition 原文存放根目录，为空则使用数据中的数据
	 * @param filePath 临时文件路径
	 * @param progressFrame 进度显示窗口对象
	 * @param index 需要更新的校验信息在进度窗口表中的行号，通过行号更新进度
	 * @return firstArchiveNo：第一个档号	lastArchiveNo：最后一个档号	result：0 没有错误，1 有错误，-1000 出现异常
	 * @author cdg 2016年3月14日09:53:00
	 */
	protected Map<String,String> writeSomethigsTmpe(List<HashMap<String, Object>> values, String osPosition, Path filePath, ProgressFrame progressFrame,int index) {
		System.out.println("start writeSomethigs() "+Thread.currentThread().getName());
		Map<String,String> map = new HashMap<String, String>();
		try{
			if(Files.exists(filePath)){
				Files.delete(filePath);
			}
			Files.createFile(filePath);
			Count count = new Count();
			if(values!=null){
				long length = values.size();
				if(osPosition==null || "".equals(osPosition)){
					values.forEach(m->{
						if(!FileUtil.isExistsFiles((String) m.get("os_position") + (String) m.get("file_loc") + (String) m.get("file_name"),(String) m.get("os_position") + (String) m.get("file_loc") + (String) m.get("file_id")+"." + (String) m.get("file_type"))){
							try {
								if(!count.getArchiveNo().equals(m.get("archive_no"))){
									
									if("".equals(count.getArchiveNo())){
										map.put("firstArchiveNo", (String) m.get("archive_no"));
									}else{
										map.put("lastArchiveNo", (String) m.get("archive_no"));
										Files.write(filePath, (System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
									}
									count.setArchiveNo((String) m.get("archive_no"));
									count.setCount(1);
									Files.write(filePath, ("%num%. " +(String) m.get("archive_no") +" "+(String) m.get("maintitle") +" "+(String) m.get("tble_name") +System.getProperty("line.separator")).getBytes(), StandardOpenOption.APPEND);
								}
								Files.write(filePath, ("\t"+count.getCount()+".  "+(String) m.get("os_position") +(String) m.get("file_loc") + (String) m.get("file_name")+System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
						progressFrame.updateProgressCheck(count.getProgress()+"/"+length, progressFrame.getRowCheck(index), 1);
					});
				}else{
					values.forEach(m->{
						if(!FileUtil.isExistsFiles(osPosition + (String) m.get("file_loc") + (String) m.get("file_name"),(String) m.get("os_position") + (String) m.get("file_loc") + (String) m.get("file_id")+"." + (String) m.get("file_type"))){
							try {
								if(!count.getArchiveNo().equals(m.get("archive_no"))){
									if("".equals(count.getArchiveNo())){
										map.put("firstArchiveNo", (String) m.get("archive_no"));
									}else{
										map.put("lastArchiveNo", (String) m.get("archive_no"));
										Files.write(filePath, (System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
									}
									count.setArchiveNo((String) m.get("archive_no"));
									count.setCount(1);
									//									sb.append(System.getProperty("line.separator")+count.getNum()+". " +(String) m.get("archive_no") +" "+(String) m.get("maintitle") +" "+(String) m.get("tble_name") +System.getProperty("line.separator"));
									Files.write(filePath, ("%num%. " +(String) m.get("archive_no") +" "+(String) m.get("maintitle") +" "+(String) m.get("tble_name") +System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
								}
								//								sb.append("\t"+count.getCount()+".  "+osPosition +(String) m.get("file_loc") + (String) m.get("file_name")+System.getProperty("line.separator"));
								Files.write(filePath, ("\t"+count.getCount()+".  "+osPosition +(String) m.get("file_loc") + (String) m.get("file_name")+System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
						progressFrame.updateProgressCheck(count.getProgress()+"/"+length, progressFrame.getRowCheck(index), 1);
					});
				}
				
			}
			else{
				Files.write(filePath, ("数据库不存在原文记录！"+System.getProperty("line.separator")).getBytes(),StandardOpenOption.APPEND);
			}
			progressFrame.removeOneCheck(index);
			if(count.getCount()>1){
				map.put("result", "1");
			}else{
				map.put("result", "0");
			}
		} catch (IOException e) {
			e.printStackTrace();
			map.put("result", "-10000");
		}
		return map;
	}
	
	
	class Count{
		int count=1;
		int num = 1;
		int progress=1;
		public int getProgress() {
			return progress++;
		}
		public int getProgressV() {
			return progress;
		}
		public void setProgress(int progress) {
			this.progress = progress;
		}
		
		String archiveNo="";
		public int getCount() {
			return count++;
		}
		public int getNumV() {
			return num;
		}
		public int getNum() {
			return num++;
		}
		public void setCount(int count) {
			this.count = count;
		}
		public void setNum(int num) {
			this.num = num;
		}
		public String getArchiveNo() {
			return archiveNo;
		}
		public void setArchiveNo(String archiveNo) {
			this.archiveNo = archiveNo;
		}
	}

}
